package org.carpediem.conman.client;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.multipart.MultiPart;
import org.apache.commons.cli.CommandLine;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocCollector;
import org.carpediem.conman.api.ConMan;
import org.carpediem.schema.conman.*;

import javax.ws.rs.core.MediaType;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ConmanClient extends Base {
    private static Logger logger = Logger.getLogger(ConmanClient.class.getName());
    private final String BASE_URI = "http://localhost:8080/conman/services";

    public static void main(String[] args) {
        logger.getParent().setLevel(Level.FINEST);
        logger.setLevel(Level.FINEST);

        ConmanClient client = new ConmanClient();
        try {
            client.run(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void run(String[] args) throws org.apache.commons.cli.ParseException {
        CommandLine cmdLine = buildOptions(args);
        if (cmdLine.hasOption('c')) {
            createContact(cmdLine.getOptionValue('e'), cmdLine.getOptionValue('d'), cmdLine.getOptionValue('m'));
        } else if (cmdLine.hasOption('a')) {
            addDocument(Integer.parseInt(cmdLine.getOptionValue('i')), cmdLine.getOptionValue('d'), cmdLine.getOptionValue('m'));
        } else if (cmdLine.hasOption('n')) {
            addNote(Integer.parseInt(cmdLine.getOptionValue('i')), cmdLine.getOptionValue('t'));
        } else if (cmdLine.hasOption('q')) {
            query(cmdLine.getOptionValue('f'), cmdLine.getOptionValue('s'));
        } else if (cmdLine.hasOption('F')) {
            newFirm(cmdLine.getOptionValue('u'));
        }
    }

    private void newFirm(String url) {
        FirmInfo firmInfo = firmInfo(url);
        logger.info(toXml(firmInfo));

        Client client = Client.create();
        WebResource service = client.resource(BASE_URI);

        firmInfo = service.path("/firms").type(MediaType.APPLICATION_XML_TYPE).post(FirmInfo.class, firmInfo);
        logger.info(toXml(firmInfo));
    }

    private FirmInfo firmInfo(String url) {
        FirmInfo fInfo = new FirmInfo();
        BFirmInfo bInfo = new BFirmInfo();
        bInfo.setUrl(url);
        fInfo.setFirm(bInfo);
        return fInfo;
    }

    private void query(String key, String value) {
        System.out.println("query with: " + key + ", " + value);
        try {
            QueryParser parser = new QueryParser(key, new StandardAnalyzer());
            org.apache.lucene.search.Query query = parser.parse(value);
            IndexSearcher is = new IndexSearcher(System.getProperties().getProperty("user.home") + "/conman/lucene");
            TopDocCollector collector = new TopDocCollector(10);
            is.search(query, collector);
            ScoreDoc[] hits = collector.topDocs().scoreDocs;

            System.out.println("Hits: " + hits.length);
            for (ScoreDoc hit : hits) {
                int docId = hit.doc;
                Document document = is.doc(docId);
                StringBuilder sb = new StringBuilder();
                sb.append("Document: ").append(document.get("LuceneType")).append(" ").append(document.get("uri"));
                System.out.println(sb);
            }

        } catch (IOException e) {
            logger.log(Level.WARNING, "IO Exception during index check", e);
        } catch (ParseException e) {
            logger.log(Level.WARNING, "Parse Exception during index check", e);
        }
    }

    private void createContact(String emailAddress, String documentFile, String mimeType) {
        ContactInfo cInfo = cInfo(emailAddress, documentFile, mimeType);

        Client client = Client.create();
        WebResource service = client.resource(BASE_URI);

        MultiPart mp = null;
        try {
            mp = new MultiPart()
                    .bodyPart(cInfo, MediaType.APPLICATION_XML_TYPE)
                    .bodyPart(new FileInputStream(documentFile), MediaType.APPLICATION_OCTET_STREAM_TYPE);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        cInfo = service.path("/contacts").type(ConMan.MULTIPART_MIXED).post(ContactInfo.class, mp);
        logger.info(toXml(cInfo));
    }

    private void addDocument(int contactId, String documentFile, String mimeType) {
        ContactInfo cInfo = cInfo(contactId, documentFile, mimeType);
        logger.info(toXml(cInfo));

        Client client = Client.create();
        WebResource service = client.resource(BASE_URI);

        MultiPart mp = null;
        try {
            mp = new MultiPart()
                    .bodyPart(cInfo, MediaType.APPLICATION_XML_TYPE)
                    .bodyPart(new FileInputStream(documentFile), MediaType.APPLICATION_OCTET_STREAM_TYPE);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        try {
            XDocumentInfo dInfo = service.path("/contacts/" + contactId + "/documents").type(ConMan.MULTIPART_MIXED).post(XDocumentInfo.class, mp);
            logger.info(toXml(dInfo));
        } catch (UniformInterfaceException e) {
            logger.log(Level.WARNING, "POST exception", e);
        }
    }

    private void addNote(int contactId, String note) {
        NoteInfo nInfo = nInfo(note);
        logger.info(toXml(nInfo));

        Client client = Client.create();
        WebResource service = client.resource(BASE_URI);

        NoteInfo contact = service.path("/contacts/" + contactId + "/notes").type(MediaType.APPLICATION_XML_TYPE).post(NoteInfo.class, nInfo);
        logger.info(toXml(contact));
    }

}
